//Virtual Crypded Disk 


#include "vcryd.h"

PDRIVER_OBJECT gDriverObject;






extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegisrtryPath)
{
	NTSTATUS 		status=STATUS_SUCCESS;             // winAPI driver status
	PDEVICE_OBJECT 	pDeviceObject;  //
	UNICODE_STRING	DeviceName;    //
	UNICODE_STRING	SymbolicLinkName;//symbol link to device 
	PDEVICE_EXTENSION pDeviceExtension;
	gDriverObject=DriverObject;
	//DbgPrint("VCRYD DriverEntry File compiled %s  %s",__DATE__,__TIME__);
	KdPrint(("VCRYD DriverEntry File compiled %s  %s",__DATE__,__TIME__));
	
	//creation of device to work with
	RtlInitUnicodeString(&DeviceName, L"\\Device\\vcryd");
	

	
	status = IoCreateDevice(IN        DriverObject,			// pointer on DriverObject
		IN        sizeof(DEVICE_EXTENSION),					// additional size of memory //sizeof(DEVICE_EXTENTION)
		IN		  &DeviceName,								// pointer to UNICODE_STRING
		IN        FILE_DEVICE_NULL,							// Device type
		IN        0,										// Device characteristic
		IN        FALSE,									// "Exclusive" device
		OUT       &pDeviceObject);							// pointer do device object
					if (status != STATUS_SUCCESS)
					{
						//DbgPrint("VCRYD DriverEntryDevice Creation Fails");
						KdPrint(("VCRYD DriverEntryDevice Creation Fails"));
						return STATUS_FAILED_DRIVER_ENTRY;
					}
	
//Symbolic link to interprocess comunication
	RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\vcrydisk");
	status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
	
				if (status != STATUS_SUCCESS)
					{
						
						KdPrint(("FAILED_CreateSymbolicLink line(%d) status%x\n",__LINE__,status));
						return STATUS_FAILED_DRIVER_ENTRY;
					}
				KdPrint(("KdprintDevice created%x\n in%s",pDeviceObject,__FUNCTION__));
				

	// let's go!!!!!!!
	pDeviceExtension=(PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
	RtlZeroMemory(pDeviceExtension,sizeof(DEVICE_EXTENSION));
	pDeviceExtension->file_size.QuadPart=(LONGLONG)  100*64*SECTOR_SIZE;//to fit grive geometry  look IOCTL_GET_DRIVE_GEOMETRY;
	pDeviceExtension->DriveLetter='C';
	//status=openMockFile(pDeviceObject);

	//read-write function pointers
	DriverObject->MajorFunction[IRP_MJ_READ] = VCRYDReadWriteDispatch;
	DriverObject->MajorFunction[IRP_MJ_WRITE] = VCRYDReadWriteDispatch;


	//other thread function pointers
	DriverObject->MajorFunction[IRP_MJ_CREATE] = VCRYDCreate;
	DriverObject->MajorFunction[IRP_MJ_CLEANUP] = VCRYDCreate;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = VCRYDCreate;

	//Device control IRP Request
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VCRYDControl;
	DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]= VCRYDDispatchSystemControl;
	//Unload procedure
	DriverObject->DriverUnload = VCRYDUnload;
	DbgPrint("VCRYD end of DriverEntry line(%d) status%x\n",__LINE__,status);
	//return status;

	//thread creation
	
			
	return status;

}

//working procedures




extern "C"  NTSTATUS VCRYDCreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp)
{
	/*
	Procedure called by IO manager when volum mounted fo system
	
	*/
	NTSTATUS status = STATUS_SUCCESS;
	ULONG byteSent = 0;//bytes read from user
	DbgPrint("in %s\n",__FUNCTION__);
	DbgPrint("PDEVICE_OBJECT=%x\n",pDeviceObject);
	
	status = CompleteIrp(Irp, status, byteSent);
	return status;
}

extern "C" NTSTATUS VCRYDDispatchSystemControl(IN PDEVICE_OBJECT gDeviceObject, IN PIRP Irp)
 
{ 
	NTSTATUS status=STATUS_SUCCESS;
	DbgPrint("DispatchSystemControl");
	IoSkipCurrentIrpStackLocation(Irp);
	return status;
}
extern "C" NTSTATUS VirtualCryptedDiskAddDevice(__in struct _DRIVER_OBJECT  *DriverObject, __in struct _DEVICE_OBJECT  *PhysicalDeviceObject)
{
	//For P/n/p drivers procedure
	// Taking PDO making FDO
	NTSTATUS	status = STATUS_SUCCESS;
	DbgPrint("--------------------------------in VirtualCryptedDiskAddDevice\n");
	return status;
}
extern "C" NTSTATUS VCRYDOpenImageFile(IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp)
{
	NTSTATUS				status = STATUS_SUCCESS;
	UNICODE_STRING			fileName;
	OBJECT_ATTRIBUTES		objectAttributes;
	PDEVICE_EXTENSION		pDeviceExtension;
	//file opening variables and structures
	
	HANDLE					hFile;
	IO_STATUS_BLOCK			ioStatusBlock;
	POPEN_FILE_INFORMATION pOpenFileInformation;

	//asserting correct parameters
	PAGED_CODE();
	ASSERT(pDeviceObject != NULL);
	ASSERT(Irp != NULL);
	
	//casting device extention
	pDeviceExtension = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;

	
	
	//getting OPEN_FILE_INFORMATION from IRP
	pOpenFileInformation = (POPEN_FILE_INFORMATION)Irp->AssociatedIrp.SystemBuffer;   //be carefull with memorysize
	pDeviceExtension->read_only = pOpenFileInformation->ReadOnly;
	pDeviceExtension->file_name.Length = pOpenFileInformation->FileNameLength;
	pDeviceExtension->file_name.MaximumLength = pOpenFileInformation->FileNameLength;
	pDeviceExtension->DriveLetter=pOpenFileInformation->DriveLetter;
	
	LPWSTR name =(LPWSTR)((PCHAR)Irp->AssociatedIrp.SystemBuffer+sizeof(OPEN_FILE_INFORMATION));
	RtlInitUnicodeString(&fileName,name);
	
	//macro initialise object_atribute structure
	InitializeObjectAttributes(&objectAttributes, &fileName,
		OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
		NULL, NULL);
	
	
	//Opening file getting handle to opened image
		
	status = ZwCreateFile(
		&hFile,					//Handle
		GENERIC_ALL,				//Read and write access
		&objectAttributes,					//atributes name size
		&ioStatusBlock, 
		NULL,								
		FILE_ATTRIBUTE_NORMAL,
		0,
		FILE_OPEN_IF,			//!Check open mode
		FILE_RANDOM_ACCESS|
		FILE_NO_INTERMEDIATE_BUFFERING|
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL, 0);
	//Checking status
	if (status != STATUS_SUCCESS)
	{
		KdPrint(("ZwCreateFile failed status=%x\tin %s\tline(%d)\n",status,__FUNCTION__,__LINE__));
		Irp->IoStatus.Status = status;
		Irp->IoStatus.Information = 0;
		return status;
	}
	
	KdPrint(("File Opened hFile=%x",hFile));
	//Reading the header
	status=ZwReadFile(	hFile,NULL,NULL,NULL,
													&Irp->IoStatus,
													&(pDeviceExtension->file_header),
													HEADER_SIZE,
													NULL,//&pIrpStack->Parameters.Read.ByteOffset,
													NULL
													);

	KdPrint(("password=%c[1] %c[16], key=%c[1]%c[16]",pDeviceExtension->file_header.password[0],pDeviceExtension->file_header.password[15],pDeviceExtension->file_header.key[0],pDeviceExtension->file_header.key[15]));
	
	/*FILE_POSITION_INFORMATION FileInformation;
	FileInformation.CurrentByteOffset.QuadPart=HEADER_OFFSET;
	
	status= ZwSetInformationFile(
	IN   hFile,
	 OUT  &ioStatusBlock,
	IN   (PVOID)&FileInformation,
	IN   sizeof(FILE_POSITION_INFORMATION),
	IN   FilePositionInformation			//File information class
);
	
	if(status!=STATUS_SUCCESS)
	{
		KdPrint(("--------------------------ZwSetInformationFile failed status=%x\tin %s\tline(%d)\n",status,__FUNCTION__,__LINE__));
		Irp->IoStatus.Status = status;
		Irp->IoStatus.Information = 0;
		return status;
	}
	*/
	//Setting device extentions
	pDeviceExtension->file_handle = hFile;
	pDeviceExtension->media_in_device = TRUE;
	pDeviceExtension->file_size.QuadPart=pOpenFileInformation->FileSize.QuadPart-HEADER_OFFSET;
	
	
	return status;
}
extern "C" NTSTATUS VCRYDCloseImageFile(IN PDEVICE_OBJECT pDeviceObject)
{
	DbgPrint("in %s\n",__FUNCTION__);
	NTSTATUS status = STATUS_SUCCESS;
	PDEVICE_EXTENSION pDeviceExtension=0;
	
	PAGED_CODE();
	ASSERT(pDeviceObject != NULL);
	

	pDeviceExtension = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
	
	//ExFreePool(pDeviceExtension->file_name.Buffer);

	status=ZwClose(pDeviceExtension->file_handle);
	if(status!=STATUS_SUCCESS)
	{
		//DbgPrint("can't close file status=%x\n",status);
		KdPrint(("can't close file status=%x\n",status));
		return status;
	}
	pDeviceExtension->media_in_device = FALSE;
	//DbgPrint("in VirtualCryptedDiskCloseImageFile returned success\n");	
	KdPrint(("in VirtualCryptedDiskCloseImageFile returned success\n"));
	return status;
}

extern "C" void VCRYDUnload(IN PDRIVER_OBJECT pDriverObject)
{
	//KdPrint("VirtualCryptedDiskUnload\n");
	NTSTATUS status=STATUS_SUCCESS;
	PDEVICE_OBJECT DeviceObjectList[20];
    ULONG DeviceObjectListSize=20;
    ULONG ActualNumberDeviceObjects=0;
	
	//give here device object pointer
	status= IoEnumerateDeviceObjectList(
		IN   pDriverObject,
		OUT  DeviceObjectList,
		IN	 DeviceObjectListSize,
		OUT	 &ActualNumberDeviceObjects
	);
	for(ULONG i=0;i<ActualNumberDeviceObjects;i++) ObDereferenceObject(DeviceObjectList[i]);
	for(ULONG i=0;i<ActualNumberDeviceObjects;i++)
	{
		PDEVICE_EXTENSION pDeviceExtension=(PDEVICE_EXTENSION)DeviceObjectList[i]->DeviceExtension;
		if(pDeviceExtension->DriveLetter=='C')
		{
		WCHAR SymbolicLinkNameString[30];
		UNICODE_STRING SymbolicLinkName;
		RtlStringCbPrintfW(SymbolicLinkNameString,60,L"\\DosDevices\\vcrydisk",pDeviceExtension->DriveLetter);
		RtlInitUnicodeString(&SymbolicLinkName,SymbolicLinkNameString);
		IoDeleteSymbolicLink(&SymbolicLinkName);
		IoDeleteDevice(DeviceObjectList[i]);
		}
		else
		{
		status=VCRYDdismountVirtualDisk(DeviceObjectList[i]);
		}
		//KdPrint("dismountVirtualDisk status=%x",status);
	}
	DbgPrint("vcryd Driver Unloaded\n");
}
extern "C" NTSTATUS VCRYDdismountVirtualDisk(PDEVICE_OBJECT pDeviceObject)
{
	DbgPrint("in %s\n",__FUNCTION__);
	NTSTATUS status=STATUS_SUCCESS;
	if(pDeviceObject==NULL)return STATUS_INVALID_PARAMETER;
	PDEVICE_EXTENSION pDeviceExtension=(PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
	//terminate thread
	pDeviceExtension->terminate_thread = TRUE;
	KeSetEvent(	&pDeviceExtension->request_event,
				(KPRIORITY)0,
				FALSE
				);
	
	status=VCRYDCloseImageFile(pDeviceObject);
	if(status!=STATUS_SUCCESS)
	{
		DbgPrint("in%s line(%d)status=%x\n",__FUNCTION__,__LINE__,status);
	}
	
	WCHAR SymbolicLinkNameString[30];
	UNICODE_STRING SymbolicLinkName;
	RtlStringCbPrintfW(SymbolicLinkNameString,60,L"\\Global??\\%c:",pDeviceExtension->DriveLetter);
	RtlInitUnicodeString(&SymbolicLinkName,SymbolicLinkNameString);
	
	IoDeleteSymbolicLink(&SymbolicLinkName);
	IoDeleteDevice(pDeviceObject);
	//KdPrint("dismountVirtualDisk status=%x",status);
	return status;

}
